--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Commit 91424b2d455562a37a37340110dc8b8eb6497f80
Parents : d800352
Author : Ivan <ivan@quad4.io>
Signature : Signature validation error
Date : 2026-04-23T04:36:05-05:00
feat(changelog): update
Changes
Diff
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 18f008ea..ff676773 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -111,6 +111,21 @@ All notable changes to this project will be documented in this file.
- **Docs**: Raspberry Pi install guide expanded with automated setup scripts and service-oriented instructions; root **README** and translated install docs note **Poetry** **2.3.4** and **pnpm** **v10+** lifecycle behaviour; **README** APK section calls out **slim** vs **full** / ABI packaging; **NomadNet** browser and **Mesh Server** page documentation added.
- **Container / compose**: **`docker-compose.yml`** and related Docker notes updated; optional **`Dockerfile.extra`** for layered builds where documented.
+### Security
+
+- **Android WebView**: **`MainActivity`** **`WebViewClient.shouldOverrideUrlLoading`** blocks top-level navigations except **`http`/`https`** to **loopback** hosts (**`127.0.0.1`**, **`localhost`**, **`::1`** / **`[::1]`**), plus **`about:blank`**, **`blob:`**, and **`data:`**, so external clearnet URLs cannot be opened inside the embedded browser.
+- **Electron shell paths**: **`showPathInFolder`** and **`openPath`** IPC handlers validate paths against allowed roots (**default storage**, **Reticulum config**, **`userData`**, **temp**, **downloads**, **documents**, **portable** bundle dir when set, and **`--storage-dir`** / **`--reticulum-config-dir`** from argv) via **`electron/shellPathGuard.js`**; out-of-tree paths are rejected.
+- **LibreTranslate / SSRF**: Client-supplied **`libretranslate_url`** (languages query and translate JSON) must target **loopback** only (**`http_url_guard.normalize_loopback_http_service_base`**); server default **`LIBRETRANSLATE_URL`** is unchanged. Outbound LibreTranslate **`aiohttp`** calls use **`allow_redirects=False`**. Invalid URLs return **HTTP 400** from the translator API routes.
+- **CSP**: Removed **`'unsafe-eval'`** from default script policy; **main SPA** responses use **`script-src 'self'`** only, while **`/rnode-flasher/`** and **`/reticulum-docs/`** keep **`'unsafe-inline'`** for their inline scripts. **Service worker** registration moved from **`index.html`** into **`main.js`** so the shell does not rely on an inline script tag. Electron session **fallback CSP** drops **`'unsafe-eval'`** as well.
+- **Electron external URLs**: **`electron/safeExternalUrl.js`** **`normalizeExternalUrlForOpen`** gates **`shell.openExternal`** in **`electron/main.js`** (**`setWindowOpenHandler`** fallback and context-menu **Open link**) and **`electron/main-legacy.js`**, allowing only **`http:`**, **`https:`**, and **`mailto:`**; **`javascript:`**, **`data:`**, **`file:`**, and other schemes are dropped. **`tests/electron/safeExternalUrl.test.js`** adds regression and light fuzz coverage.
+- **Chat link rendering**: **`meshchatx/src/frontend/js/LinkUtils.js`** **`renderStandardLinks`** validates detected URLs with the **`URL`** constructor (with an **`&` → `&`** retry for HTML-escaped query strings), omits linkification when parsing fails or the scheme is not **`http`/`https`**, excludes **`'`** and **`"`** from the autolink detector tail, HTML-escapes link labels, and HTML-escapes **`data-nomadnet-url`** attribute values. **`tests/frontend/LinkUtils.test.js`** / **`MarkdownRenderer.test.js`** updated for canonical **`href`** output.
+- **Tests**: **`tests/backend/test_http_url_guard.py`** (loopback URL edge cases and rejections), **`tests/electron/shellPathGuard.test.js`**, and **`tests/electron/safeExternalUrl.test.js`** cover URL and path rules.
+- **Repository uploads**: **`tests/backend/test_repository_server_manager.py`** parametrized rejects for **`save_upload`** filenames outside **`_safe_any_upload_filename`** (**`repository_server_manager.py`**).
+- **Map deep links and map ping classification**: **`meshchatx/src/frontend/js/mapLinkUtils.js`** **`mapLinkKindFromMessage`** now requires the localized **MeshChatX map ping** prefix at the **start** of the message (after optional whitespace) with a **word boundary**, so a ping cannot be spoofed by embedding that phrase inside HTML or other text. Backend coverage in **`tests/backend/test_deep_links_security.py`** for **`lxm.ingest_uri`** **`meshchatx://map` / `meshchat://map`** (including XSS-shaped **`layers`** / **`label`** query values and Hypothesis fuzzing); frontend coverage in **`tests/frontend/mapLinkUtils.security.test.js`**, **`tests/frontend/deepLinks.protocol.security.test.js`**, and updates to **`tests/frontend/mapLinkUtils.test.js`**.
+- **Interface discovery numerics**: **`meshchatx/src/frontend/js/interfaceDiscoveryUtils.js`** **`numOrNull`** only accepts **`string`** and **`number`** (no **`Number([])`**, **`Number({ valueOf })`**, or other object coercion). **`tests/frontend/interfaceDiscoveryUtils.security.test.js`** and **`tests/frontend/interfaceDiscoveryUtils.test.js`** cover edge cases.
+- **Discovered interface list payloads (backend)**: **`tests/backend/test_discovered_interfaces_security.py`** fuzzes **`ReticulumMeshChat.discovery_filter_candidates`**, **`matches_discovery_pattern`**, **`sanitize_discovery_patterns`**, and **`filter_discovered_interfaces`** with very long names, HTML/script-like strings, and arbitrary extra keys, and asserts **`json.dumps`** on filtered results.
+- **Stickers, GIFs, and LXMF reactions (backend + frontend)**: **`tests/backend/test_media_sticker_reaction_gif_security.py`** Hypothesis-fuzzes **`meshchatx/src/backend/sticker_utils.py`** (**`sanitize_sticker_name`**, **`sanitize_sticker_emoji`**, **`normalize_image_type`**), **`gif_utils`** (**`sanitize_gif_name`**, **`normalize_image_type`**, **`validate_gif_payload`** / export documents), **`sticker_pack_utils`** pack string sanitizers, and **`lxmf_utils.convert_lxmf_message_to_dict`** with hostile **`app_extensions`** reaction fields. **`tests/frontend/lxmfReactions.test.js`** and **`tests/frontend/inViewObserver.test.js`** add reaction-merge and raster-type edge cases.
+
### Testing and docs
- **Frontend**: **`AppPropagationSync.test.js`** covers immediate completion (no stray loading toast), polling with **`path_requested`** and live **`ToastUtils.loading`**, and **`no_path`** end states with translated error text; **`AppModals`** / **`ChangelogModal`** tests updated where changelog content or expectations shifted.
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────